#include "imageset.h"

#include <ctype.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static char* token;
static char* er;
static jmp_buf buf;

static void next_token(FILE* f)
{
	if(fscanf(f, "%255s", token) == 0)
	{
		er = "Unexpected end of file.";
		longjmp(buf, 1);
	}
}


static void expect_token(FILE* f, char* id)
{
	if(strcmp(token, id) != 0)
	{
		er = "Expected ID.";
		longjmp(buf, 1);
	}
	next_token(f);
}


static uint8_t expect_hex(FILE *f)
{
	int i;
	for(i=0; token[i]; i++)
		if(!isalnum(token[i]))
		{
			er = "Expected hexadecimal number.";
			longjmp(buf, 1);
		}

	uint8_t v = strtol(token, NULL, 16);
	next_token(f);
	return v;
}


static uint8_t expect_dec(FILE *f)
{
	int i;
	for(i=0; token[i]; i++)
		if(!isdigit(token[i]))
		{
			er = "Expected decimal number.";
			longjmp(buf, 1);
		}

	uint8_t v = strtol(token, NULL, 10);
	next_token(f);
	return v;
}


static char* expect_string(FILE *f) // TODO - check closing quotes
{
	char* s = calloc(strlen(token), 1);
	int i;
	for(i=1; token[i] != '"'; i++)
		s[i-1] = token[i];
	s[i] = '\0';
	next_token(f);
	return s;
}


void parse_colormap(Imageset *is, FILE* f)
{
	expect_token(f, "{");
	while(strcmp(token, "}") != 0)
	{
		uint8_t color = expect_hex(f);
		expect_token(f, ":");
		char* name = expect_string(f);
		expect_token(f, "[");
		uint8_t r = expect_hex(f);
		uint8_t g = expect_hex(f);
		uint8_t b = expect_hex(f);
		expect_token(f, "]");
		
		imageset_setcolor(is, color, r, g, b, name);
		free(name);
	}
	expect_token(f, "}");
}


void parse_image(Imageset *is, FILE* f)
{
	expect_token(f, "{");

	uint16_t w = 0, h = 0;
	char* name = NULL;
	uint8_t* data = NULL;

	while(strcmp(token, "}") != 0)
	{
		if(strcmp(token, "name") == 0)
		{
			next_token(f);
			name = expect_string(f);
		}
		else if(strcmp(token, "width") == 0)
		{
			next_token(f);
			w = expect_dec(f);
		}
		else if(strcmp(token, "height") == 0)
		{
			next_token(f);
			h = expect_dec(f);
		}
		else if(strcmp(token, "data") == 0)
		{
			next_token(f);
			expect_token(f, "{");
			data = malloc(w * h);
			int i;
			for(i=0; i<(w*h); i++)
				data[i] = expect_hex(f);
			expect_token(f, "}");
		}
		else
		{
			er = "Expected 'name', 'height', 'width' or 'data'.";
			longjmp(buf, 1);
		}
	}

	Image* img = imageset_addimage(is, w, h, name);
	free(name);
	free(img->data);
	img->data = data;
	
	expect_token(f, "}");
}


Imageset* imageset_input(FILE* f)
{
	token = malloc(255);
	next_token(f);

	expect_token(f, "imageset");
	expect_token(f, "{");

	Imageset* is = imageset_new();

	// exception handling
	if(setjmp(buf))
	{
		fprintf(stderr, "%s\n", er);
		free(token);
		return NULL;
	}
	
	// parse
	while(strcmp(token, "}") != 0)
	{
		if(strcmp(token, "colormap") == 0)
		{
			next_token(f);
			parse_colormap(is, f);
		}
		else if(strcmp(token, "image") == 0)
		{
			next_token(f);
			parse_image(is, f);
		}
		else
		{
			er = "Expected 'colormap' or 'image'.";
			free(token);
			return NULL;
		}
	}

	free(token);
	return is;
}
